package ex1;

/**
 * NormalCell implements ICell.
 * Implements a normal, <b>INNER</b>, cell which never interacts with other threads besides its owner.
 */
public class NormalCell implements ICell {
	
	protected ICell neighbours[];
	protected int maxGen, currGen;
	protected boolean currState, prevState;

	/**
	 * Constructor for a normal cell.
	 * 
	 * @param state The initial state of the cell.
	 * @param maxGen The maximal generation this cell should reach.
	 */
	public NormalCell (boolean state, int maxGen) {
		this.maxGen = maxGen;
		currGen = 0;
		currState = state;
		prevState = state;
		neighbours = new ICell[8];
	}
	
	/* 
	 * (non-Javadoc)
	 * @see ex1.ICell#canEvolve()
	 */
	public boolean canEvolve () {
		try {
		for (ICell n : neighbours)
			n.getState(currGen);
		}
		catch (NotReady n) { return false; }
		return true;
	}
	
	/*
	 * (non-Javadoc)
	 * @see ex1.ICell#done()
	 */
	public boolean done () {
		return currGen >= maxGen;
	}
	
	/*
	 * (non-Javadoc)
	 * @see ex1.ICell#evolve()
	 */
	public boolean evolve() {
		if (currGen >= maxGen)
			return false;
		try {
			int alive = liveNeighbours();
			if (alive == 3 || (currState && alive == 2))
				nextState(true);
			else
				nextState(false);
			return true;
		}
		catch (NotReady n) { return false; }
	}
	
	/**
	 * Counts the live neighbours of the cell, in its current generation.
	 * 
	 * @return number of living neighbours in the current generation.
	 * @throws NotReady if there's a neighbour which isn't ready.
	 */
	protected int liveNeighbours () throws NotReady {
		int alive = 0;
		for (ICell c : neighbours)
			if (c.getState(currGen))
				alive++;
		return alive;
	}
	
	/**
	 * Sets the next desired state for the cell.
	 * 
	 * @param state next state.
	 */
	protected void nextState (boolean state) {
		prevState = currState;
		currState = state;
		currGen++;
	}

	/*
	 * (non-Javadoc)
	 * @see ex1.ICell#getState(int)
	 */
	public boolean getState(int generation) throws NotReady {
		if (generation == currGen)
			return currState;
		if (generation == currGen - 1)
			return prevState;
		throw new NotReady();
	}

	/*
	 * (non-Javadoc)
	 * @see ex1.ICell#init(ex1.ICell, ex1.ICell, ex1.ICell, ex1.ICell, ex1.ICell, ex1.ICell, ex1.ICell, ex1.ICell)
	 */
	public void init(ICell tl, ICell tm, ICell tr, ICell l, ICell r, ICell bl, ICell bm, ICell br) {
		neighbours[0] = tl; neighbours[1] = tm; neighbours[2] = tr;
		neighbours[3] = l;                      neighbours[4] = r;
		neighbours[5] = bl; neighbours[6] = bm; neighbours[7] = br;
	}

	/**
	 * Since we're dealing with a normal cell which is inside a thread, it won't have to wake anyone up.
	 * 
	 * @see ICell#wakeOwner()
	 */
	public void wakeOwner () {
		// gurnisht.
	}
	
}
